﻿// Inner Fire 游戏引擎库
// Lua绑定适配项目
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 用于物理系统的Lua绑定适配。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-06-17

#include "lua_manager.h"
#include <game/object/game_object.h>
#include <game/object/transform.h>
#include <game/physics/chara_controller.h>
#include <game/physics/collider.h>
#include <game/physics/collision.h>
#include <game/physics/physics_world.h>
#include <game/physics/rigid_body.h>

namespace ifire::game {

static int RigidBody_SetPosition(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetPosition(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}
static int RigidBody_GetPosition(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  return ikit::lua_return_float3(L, ptr->GetPosition());
}

static int RigidBody_SetRotation(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetRotationEuler(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}
static int RigidBody_GetRotation(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  return ikit::lua_return_float3(L, ptr->GetRotationEuler());
}

static int RigidBody_SetScale(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetScale(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}
static int RigidBody_GetScale(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  return ikit::lua_return_float3(L, ptr->GetScale());
}

static int RigidBody_SetVelocity(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetVelocity(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int RigidBody_SetAcceleration(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetAcceleration(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int RigidBody_SetMass(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetMass(L_FLOAT(2));
  return 0;
}

static int RigidBody_SetRestitution(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetRestitution(L_FLOAT(2));
  return 0;
}

static int RigidBody_SetRadius(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetRadius(L_FLOAT(2));
  return 0;
}

static int RigidBody_AddForce(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->AddForce(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int RigidBody_AddTorque(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->AddTorque(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int RigidBody_AddGravity(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->AddGravity(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int RigidBody_AddDrag(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->AddDrag(L_FLOAT(2));
  return 0;
}

static int RigidBody_AddFriction(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->AddFriction(L_FLOAT(2));
  return 0;
}

static int RigidBody_ApplyImpulse(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->ApplyImpulse(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int RigidBody_AddSpring(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  auto anchor = XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4));
  ptr->AddSpring(anchor, L_FLOAT(5), L_FLOAT(6));
  return 0;
}

static int RigidBody_SetParticle(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetParticle();
  return 0;
}

static int RigidBody_SetSphere(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetSphere(L_FLOAT(2));
  return 0;
}

static int RigidBody_SetBox(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetBox(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int RigidBody_SetCapsule(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  ptr->SetCapsule(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4));
  return 0;
}

static int RigidBody_IsColliding(lua_State* L) {
  auto ptr = L_THIS(RigidBody);
  auto target = L_OBJ(2, RigidBody);
  Contact c;
  bool result = ptr->IsColliding(target, c);
  lua_pushboolean(L, result);
  return 1;
}

static int PhysicsWorld_Add(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  auto target = L_OBJ(2, RigidBody);
  ptr->Add(target);
  return 0;
}

static int PhysicsWorld_SetGravity(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->SetGravity(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int PhysicsWorld_SetDrag(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->SetDrag(L_FLOAT(2));
  return 0;
}

static int PhysicsWorld_SetFriction(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->SetFriction(L_FLOAT(2));
  return 0;
}

static int PhysicsWorld_AddForce(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->AddForce(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int PhysicsWorld_AddTorque(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->AddTorque(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int PhysicsWorld_RemoveForce(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->RemoveForce(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int PhysicsWorld_RemoveTorque(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->RemoveTorque(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int PhysicsWorld_UseCollision(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->UseCollision(L_BOOL(2));
  return 0;
}

static int PhysicsWorld_UseBox(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  ptr->UseBox(L_BOOL(2));
  return 0;
}

static int PhysicsWorld_SetWorldBox(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  auto min = XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4));
  auto max = XMFLOAT3(L_FLOAT(5), L_FLOAT(6), L_FLOAT(7));
  ptr->SetWorldBox(min, max);
  return 0;
}

static int PhysicsWorld_AddJoint(lua_State* L) {
  auto ptr = L_THIS(PhysicsWorld);
  auto a = L_OBJ(2, RigidBody);
  auto b = L_OBJ(3, RigidBody);
  auto anchor = XMFLOAT3(L_FLOAT(4), L_FLOAT(5), L_FLOAT(6));
  ptr->AddJoint(a, b, anchor);
  return 0;
}

static int Collider_GetName(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ikit::lua_push_sstr(L, ptr->game_object_->GetName());
  return 1;
}

static int Collider_SetCollider(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetCollider(L_STR(2));
  return 0;
}

static int Collider_SetParticle(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetParticle();
  return 0;
}

static int Collider_SetSphere(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetSphere(L_FLOAT(2));
  return 0;
}

static int Collider_GetSphere(lua_State* L) {
  auto ptr = L_THIS(Collider);
  lua_pushnumber(L, ptr->sphere.radius);
  return 1;
}

static int Collider_SetBox(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetBox(XMFLOAT3(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4)));
  return 0;
}

static int Collider_GetBox(lua_State* L) {
  auto ptr = L_THIS(Collider);
  return ikit::lua_return_float3(L, ptr->half_extents);
}

static int Collider_SetCenter(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetCenter(L_VEC3(2));
  return 0;
}

static int Collider_GetCenter(lua_State* L) {
  auto ptr = L_THIS(Collider);
  return ikit::lua_return_float3(L, ptr->center);
}

static int Collider_SetCapsule(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetCapsule(L_FLOAT(2), L_FLOAT(3), L_FLOAT(4));
  return 0;
}

static int Collider_GetCapsule(lua_State* L) {
  auto ptr = L_THIS(Collider);
  auto& c = ptr->capsule;
  lua_pushnumber(L, c.radius);
  lua_pushnumber(L, c.start);
  lua_pushnumber(L, c.end);
  return 3;
}

static int Collider_GetType(lua_State* L) {
  auto ptr = L_THIS(Collider);
  lua_pushinteger(L, (int)ptr->type);
  return 1;
}

static int Collider_GetTypeName(lua_State* L) {
  auto ptr = L_THIS(Collider);
  lua_pushstring(L, GetShapeTypeName(ptr->type).c_str());
  return 1;
}

static int Collider_CreateVisualObject(lua_State* L) {
  auto ptr = L_THIS(Collider);
  auto obj = ptr->CreateVisualObject();
  return ikit::lua_return_object(L, obj, "GameObjectMeta");
}

static int Collider_SetLayer(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetLayer(L_STR(2));
  return 0;
}

static int Collider_SetMask(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetMask(L_STR(2));
  return 0;
}

static int Collider_CheckCharaCollision(lua_State* L) {
  auto ptr = L_THIS(Collider);
  auto result = ptr->CheckCharaCollision();
  lua_pushinteger(L, (lua_Integer)(result));
  return 1;
}

static int Collider_SetCollideResultLimit(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->SetCollideResultLimit(static_cast<size_t>(lua_tointeger(L, 2)));
  return 0;
}

static int Collider_AddToCharaColliderWorld(lua_State* L) {
  auto ptr = L_THIS(Collider);
  ptr->AddToCharaColliderWorld();
  return 0;
}

static int Collider_GetCollisionResult(lua_State* L) {
  auto ptr = L_THIS(Collider);
  auto& result = ptr->GetCollisionResult(L_INT(2));
  ikit::lua_push_object(L, result.obj, "GameObjectMeta");
  ikit::lua_push_object(L, result.collider, "ColliderMeta");
  return 2;
}

void register_lua_physics(lua_State* L, LuaManager* lua_manager) {

  // 注册RigidBody组件
  luaL_Reg rigidbody_methods[] = {                    //
      {"SetPosition", RigidBody_SetPosition},         //
      {"GetPosition", RigidBody_GetPosition},         //
      {"SetRotation", RigidBody_SetRotation},         //
      {"GetRotation", RigidBody_GetRotation},         //
      {"SetScale", RigidBody_SetScale},               //
      {"GetScale", RigidBody_GetScale},               //
      {"SetVelocity", RigidBody_SetVelocity},         //
      {"SetAcceleration", RigidBody_SetAcceleration}, //
      {"SetMass", RigidBody_SetMass},                 //
      {"SetRestitution", RigidBody_SetRestitution},   //
      {"SetRadius", RigidBody_SetRadius},             //
      {"AddForce", RigidBody_AddForce},               //
      {"AddTorque", RigidBody_AddTorque},             //
      {"AddGravity", RigidBody_AddGravity},           //
      {"AddDrag", RigidBody_AddDrag},                 //
      {"AddFriction", RigidBody_AddFriction},         //
      {"ApplyImpulse", RigidBody_ApplyImpulse},       //
      {"AddSpring", RigidBody_AddSpring},             //
      {"SetParticle", RigidBody_SetParticle},         //
      {"SetSphere", RigidBody_SetSphere},             //
      {"SetCapsule", RigidBody_SetCapsule},           //
      {"SetBox", RigidBody_SetBox},                   //
      {"IsColliding", RigidBody_IsColliding},         //
      {NULL, NULL}};
  ikit::lua_register_metatable(L, "RigidBodyMeta", rigidbody_methods);

  // 注册PhysicsWorld
  luaL_Reg physics_world_methods[] = {             //
      {"Add", PhysicsWorld_Add},                   //
      {"SetGravity", PhysicsWorld_SetGravity},     //
      {"SetDrag", PhysicsWorld_SetDrag},           //
      {"SetFriction", PhysicsWorld_SetFriction},   //
      {"AddForce", PhysicsWorld_AddForce},         //
      {"AddTorque", PhysicsWorld_AddTorque},       //
      {"RemoveForce", PhysicsWorld_RemoveForce},   //
      {"RemoveTorque", PhysicsWorld_RemoveTorque}, //
      {"UseCollision", PhysicsWorld_UseCollision}, //
      {"SetWorldBox", PhysicsWorld_SetWorldBox},   //
      {"AddJoint", PhysicsWorld_AddJoint},         //
      {NULL, NULL}};
  ikit::lua_register_metatable(L, "PhysicsWorldMeta", physics_world_methods);

  // 注册Collider组件
  luaL_Reg collider_methods[] = {                                    //
      {"GetName", Collider_GetName},                                 //
      {"SetCollider", Collider_SetCollider},                         //
      {"SetParticle", Collider_SetParticle},                         //
      {"SetSphere", Collider_SetSphere},                             //
      {"GetSphere", Collider_GetSphere},                             //
      {"SetCapsule", Collider_SetCapsule},                           //
      {"GetCapsule", Collider_GetCapsule},                           //
      {"SetBox", Collider_SetBox},                                   //
      {"GetBox", Collider_GetBox},                                   //
      {"SetCenter", Collider_SetCenter},                             //
      {"GetCenter", Collider_GetCenter},                             //
      {"GetType", Collider_GetType},                                 //
      {"GetTypeName", Collider_GetTypeName},                         //
      {"CreateVisualObject", Collider_CreateVisualObject},           //
      {"SetLayer", Collider_SetLayer},                               //
      {"SetMask", Collider_SetMask},                                 //
      {"CheckCharaCollision", Collider_CheckCharaCollision},         //
      {"SetCollideResultLimit", Collider_SetCollideResultLimit},     //
      {"AddToCharaColliderWorld", Collider_AddToCharaColliderWorld}, //
      {"GetCollisionResult", Collider_GetCollisionResult},           //

      {NULL, NULL}};
  ikit::lua_register_metatable(L, "ColliderMeta", collider_methods);

  // 注册CharaController组件
  luaL_Reg chara_controller_methods[] = {//

      {NULL, NULL}};
  ikit::lua_register_metatable(
      L, "CharaControllerMeta", chara_controller_methods);
}

} // namespace ifire::game